package com.qf.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;

/**
 * 监听RabbitMQ中 push_sms_report_topic
 * <p>
 * 立即发送,4m,10m,10m,1h,2h,6h,15h   总发5次
 * 直到接收到success  7个字符
 *
 * @author lixu
 */
@Component
@Slf4j
public class RabbitMqListener {

    @Autowired
    private CacheFeign cacheFeign;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //延迟消息的时候
    private Integer[] sendTTL = {0, 10000, 30000, 60000, 300000};

    /*
    监听RabbitMQ中 push_sms_report_topic
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void receiverMessagePushReport(Channel channel, Message message,
                                          StandardReport standardReport) {
        try {
            //逻辑开发了
            //判断是否成功
            //基于挺迟插件的延迟消息

            //1:获取到客户端的URL地址
            //   http://localhost:8099/receive/status   http://status.jd.com/receive/status
            String clientKey = CacheConstants.CACHE_PREFIX_CLIENT + standardReport.getClientID();
            String receivestatusurl = cacheFeign.hget(clientKey, "receivestatusurl");
            if (!StringUtils.isEmpty(receivestatusurl)) {
                //2:开始推荐状态报告
                standardReport.setReceiveStatusUrl(receivestatusurl);
                //第一次发送  立即发送
                standardReport.setSendCount(1);
                //状态报告的发送状态
                standardReport.setState(1);
                //3、推送状态报告用户
                sendReport(standardReport);
            } else {
                //客户端没有给我们短信平台留下 返回状态报告的地址
                log.info("[接口模块 - 状态报告推送] 用户不需要推送状态报告!, 流程执行完毕! standardReport={}",
                        objectMapper.writeValueAsString(standardReport));
            }
            //4:直接应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送状态报告给用户
     *
     * @param standardReport
     * @return
     */
    private void sendReport(StandardReport standardReport) {
        //请求实体对象  （请求头 、请求体）
        try {
            HttpEntity httpEntity = new HttpEntity(standardReport);
            /**
             * <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
             * 			Object... uriVariables) throws RestClientException;
             * 		1、请求URL   http://localhost:8099/receive/status?name=xixi&age=22
             * 	    2、HttpRequest请求
             * 	        请求头
             * 	        请求体
             * 	    3、返回值 类型  String  success
             * 	    4、URL上的参数
             *
             */
            restTemplate.postForObject(standardReport.getReceiveStatusUrl(), httpEntity, String.class);
        } catch (Exception e) {
            //将栈中异常抛出并打印在控制台上
            log.error("[接口模块 - 状态报告推送]推送状态报告给用户抛出了异常:{}", e.getMessage());
            //发送延迟消息  第二~ 五个消息 从延迟队列中获取出来的
            delayedMessageHandler(standardReport);
            //e.printStackTrace();
        }
    }
    /**
     * 发送延迟消息   除了第一次以外 都需要延迟消息
     *   JD：发消息     //状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
     *     private Integer[] sendTTL = {0, 10000, 30000, 60000, 300000};
     *   icbc：发消息：  //状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
     *     private Integer[] sendTTL = {0, 10000, 30000, 60000, 300000};
     */
    public void delayedMessageHandler(StandardReport standardReport){
        //发送到延迟消息队列
        rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE,
                DelayedConfig.DELAYED_ROUTING_KEY,standardReport,(message) -> {
                    //设置延迟消息的时间 部局设置时间  毫s
                    message.getMessageProperties().setDelay(sendTTL[standardReport.getSendCount()]);
                    return message;
                });
    }

    /**
     * 监听器  接收延迟消息队列   第二次~第五次
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void receiverDelayedMessage(Channel channel, Message message,
                                       StandardReport standardReport){

        try {
            //1:获取客户的URL
            String receiveStatusUrl = standardReport.getReceiveStatusUrl();
            //2:第二次~第五次
            int sendCount = standardReport.getSendCount();
            if(sendCount >= 5){
                standardReport.setState(2);
                log.error("[接口模块 - 状态报告推送] 推荐5次全失败了! standardReport={}",
                objectMapper.writeValueAsString(standardReport));
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
            //接着重新发送报告
            standardReport.setSendCount(sendCount +1);
            //发送报告 给用户
            sendReport(standardReport);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
